﻿using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Ports;
using System.Runtime.InteropServices;
using System.Threading;
using LDSBusiness.EventArgs;
using LDSCore;
using LDSCore.Result;
using LDSModel.Item;

namespace LDSBusiness
{
    /// <summary>
    /// 消息接收者
    /// </summary>
    public sealed class DataRecipient : DataOperator, IDisposable
    {
#if TEST
        static int index;
#endif

        #region 数据

        /// <summary>
        /// 消息队列
        /// </summary>
        readonly Queue<MsgItem> _msgQue;

        /// <summary>
        /// 消息队列
        /// </summary>
        readonly Queue<MsgItem> _msgRecordQue;

        #endregion

        #region 线程

        /// <summary>
        /// 处理线程
        /// </summary>
        bool _exitProcessMsgThread;

        /// <summary>
        /// 处理线程
        /// </summary>
        bool _exitProcessRecordThread;

        #endregion

        #region 事件

        /// <summary>
        /// 消息处理事件事件
        /// </summary>
        public event DelegateMsgProcess OnMsgProcess;

        #endregion

        #region 属性

        /// <summary>
        /// 串口名称
        /// </summary>
        public string PortName
        {
            get { return SerialPort.PortName; }
        }

        /// <summary>
        /// 串口是否打开
        /// </summary>
        public bool IsOpen
        {
            get
            {
                if (SerialPort == null) return false;
                return SerialPort.IsOpen;
            }
        }

        #endregion

        /// <summary>
        /// 构造函数
        /// </summary>
        private DataRecipient()
        {
            _msgQue = new Queue<MsgItem>();
            _msgRecordQue = new Queue<MsgItem>();
        }

        /// <summary>
        /// 开始解析数据
        /// </summary>
        public OperationResult Start(SerialPort serialPort)
        {
            var result = new OperationResult();

            try
            {
                if (SerialPort != null)
                {
                    SerialPort.Dispose();
                    SerialPort = null;
                }
                SerialPort = serialPort;

                SerialPort.DataReceived += monitorSerialPort_DataReceived;

                ThreadExecutor.Execute(ProcessMsgHandler);
                ThreadExecutor.Execute(ProcessRecordHandler);

                SerialPort.Open();
                while (!SerialPort.IsOpen)
                {
                    Thread.Sleep(100);
                }
                result.Success = true;
            }
            catch (Exception ex)
            {
                result.Exception = ex;
            }

            return result;
        }

        #region 数据接收处理分发

        /// <summary>
        /// 串口数据接收事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void monitorSerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            SerialPort.DataReceived -= monitorSerialPort_DataReceived;

            string logFolder = AppDomain.CurrentDomain.BaseDirectory + "\\Log\\logbyte";
            try
            {
                int len;
                do
                {
                    len = SerialPort.BytesToRead;
                    Thread.Sleep(30);
                    if (!SerialPort.IsOpen) return;
                } while (SerialPort.BytesToRead != len);

                if (len == 0) return;

#if TEST
            index++;
            Thread.Sleep(30);
#endif

                var bytes = new byte[len];
                SerialPort.Read(bytes, 0, bytes.Length);

#if TEST
            Console.WriteLine(string.Format("接收数据： 线程Id({0}),序号{1},数据({2})", Thread.CurrentThread.ManagedThreadId, index, BitConverter.ToString(bytes, 0, bytes.Length)));
#endif

                ParserDataHandler(bytes);

#if DEBUG

                // 创建日志记录文件夹
                Directory.CreateDirectory(logFolder);

                #region 修正文件夹路径

                if (!logFolder.EndsWith("\\"))
                {
                    logFolder += "\\";
                }

                #endregion

                // 按日期生成文件名
                var file = logFolder + DateTime.Now.ToShortDateString().Replace('/', '-') + ".txt";

                var fs = new FileStream(file, FileMode.Append);
                var sw = new StreamWriter(fs);
                sw.WriteLine(string.Format("数据：{0}，发生时间：{1}", BitConverter.ToString(bytes, 0, bytes.Length), DateTime.Now));
                sw.Close();
                fs.Close();
            }
            catch (Exception ex)
            {
                LogFileHelper.Record(ex);
            }
            finally
            {
                SerialPort.DataReceived += monitorSerialPort_DataReceived;
            }
#endif
        }

        /// <summary>
        /// 数据接收处理线程
        /// </summary>
        void ParserDataHandler(byte[] bytes)
        {
            try
            {
                //byte[] realBytes = new byte[byteBuffer.Length + bytes.Length];
                //Array.Copy(byteBuffer, 0, realBytes, 0, byteBuffer.Length);
                //Array.Copy(bytes, 0, realBytes, byteBuffer.Length, bytes.Length);

#if _TRACE
                Console.WriteLine(string.Format("准备解析数据： 数据({0})", BitConverter.ToString(realBytes, 0, realBytes.Length)));
#endif

                bool flag = true;
                while (bytes.Length > 0 && flag)
                {
                    flag = ParserData(ref bytes);
                }

                //byteBuffer = realBytes;
            }
            catch (Exception ex)
            {
                LogFileHelper.Record(ex);
            }
        }

        /// <summary>
        /// 解析数据
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        bool ParserData(ref byte[] bytes)
        {
            // 2为校验码长度
            var minLength = Marshal.SizeOf(typeof(MsgHead)) + 2;

            if (bytes.Length < minLength)
            {
                // 异常数据
                LogFileHelper.Record(new Exception("异常数据"), string.Format("原始数据：{0}\r\n   删除数据：{1}",
                    BitConverter.ToString(bytes, 0, bytes.Length),
                    BitConverter.ToString(bytes, 0, bytes.Length)));
                return false;
            }

            var head = new MsgHead();
            head = head.FromBytes(bytes, 0);

            byte[] dataBytes;
            if (head.FrameStart == 0xAA55)
            {
                var useLength = 2;
                var dataLength = Marshal.SizeOf(typeof(MsgHead));

                // 如果包含额外数据
                if ((head.DataLength + minLength) <= bytes.Length)
                {
                    dataLength += head.DataLength;
                    dataBytes = new byte[head.DataLength];
                    Array.Copy(bytes, Marshal.SizeOf(typeof(MsgHead)), dataBytes, 0, head.DataLength);

                    var chkSum = DataSender.Instance.GetCheckSum(bytes, dataLength);

                    if (bytes[dataLength] == Convert.ToByte((chkSum / 256) & 0xFF) &&
                        bytes[dataLength + 1] == Convert.ToByte(chkSum & 0xFF))
                    {
#if _TRACE
                        Console.WriteLine(string.Format("解析数据： 数据({0})", BitConverter.ToString(bytes, 0, head.DataLength + minLength)));
#endif
                        useLength = head.DataLength + minLength;

                        var msg = new MsgItem(head, dataBytes);

                        switch ((MsgType)msg.MsgType)
                        {
                            case MsgType.ZGCMD_SEND_RECORD:
                                _msgRecordQue.Enqueue(msg);
                                break;
                            default:
                                _msgQue.Enqueue(msg);
                                break;
                        }
                    }
                    else
                    {
                        while (bytes[useLength] != 0x55 || bytes[useLength + 1] != 0xAA)
                        {
                            useLength++;

                            if (useLength >= bytes.Length)
                                break;
                        }

                        // 校验失败
                        LogFileHelper.Record(new Exception("校验数据失败"), string.Format("原始数据：{0}\r\n   校验数据：{1}\r\n   删除数据：{2}",
                            BitConverter.ToString(bytes, 0, bytes.Length),
                            BitConverter.ToString(bytes, 0, head.DataLength + minLength),
                            BitConverter.ToString(bytes, 0, useLength)));
                    }

                    dataBytes = new byte[bytes.Length - useLength];
                    Array.Copy(bytes, useLength, dataBytes, 0, dataBytes.Length);
                    bytes = dataBytes;

                    return true;
                }
                return false;
            }
            var exceptLength = 1;

            while (bytes[exceptLength] != 0x55 || bytes[exceptLength + 1] != 0xAA)
            {
                exceptLength++;

                if (exceptLength >= bytes.Length)
                    break;
            }

            // 异常数据
            LogFileHelper.Record(new Exception("异常数据"), string.Format("原始数据：{0}\r\n   删除数据：{1}",
                                                                      BitConverter.ToString(bytes, 0, bytes.Length),
                                                                      BitConverter.ToString(bytes, 0, exceptLength)));

            dataBytes = new byte[bytes.Length - exceptLength];
            Array.Copy(bytes, exceptLength, dataBytes, 0, dataBytes.Length);
            bytes = dataBytes;
            return false;
        }

        /// <summary>
        /// 消息处理分发线程
        /// </summary>
        void ProcessMsgHandler(object state)
        {
            while (true)
            {
                if (_exitProcessMsgThread)
                {
                    _exitProcessMsgThread = false;
                    return;
                }

                if (_msgQue.Count > 0)
                {
                    try
                    {
                        MsgItem msg = _msgQue.Dequeue();

#if _TRACE
                        Console.WriteLine(string.Format("记录分发： 线程Id({0}),发送地址({1}),数据({2}),时间({3})", Thread.CurrentThread.ManagedThreadId, msg.SrcAddr, JsonConvert.SerializeObject(msg), DateTime.Now));
#endif

                        if (null != OnMsgProcess)
                        {
                            OnMsgProcess(this, new MsgProcessEventArgs(msg));
                        }
                    }
                    catch (Exception ex)
                    {
                        LogFileHelper.Record(ex);
                    }
                }
                else
                {
                    Thread.Sleep(100);
                }
            }
        }

        /// <summary>
        /// 消息处理分发线程
        /// </summary>
        void ProcessRecordHandler(object state)
        {
            while (true)
            {
                if (_exitProcessRecordThread)
                {
                    _exitProcessRecordThread = false;
                    return;
                }

                if (_msgRecordQue.Count > 0)
                {
                    try
                    {
                        MsgItem msg = _msgRecordQue.Dequeue();

#if _TRACE
                Console.WriteLine(string.Format("雷击记录分发： 线程Id({0}),发送地址({1}),数据({2}),时间({3})", Thread.CurrentThread.ManagedThreadId, msg.SrcAddr, JsonConvert.SerializeObject(msg), DateTime.Now));
#endif

                        if (null != OnMsgProcess)
                        {
                            OnMsgProcess(this, new MsgProcessEventArgs(msg));
                        }
                    }
                    catch (Exception ex)
                    {
                        LogFileHelper.Record(ex);
                    }
                }
                else
                {
                    Thread.Sleep(100);
                }
            }
        }

        #endregion

        /// <summary>
        /// 停止解析数据
        /// </summary>
        public void Stop()
        {
            SerialPort.Close();
            SerialPort.DataReceived -= monitorSerialPort_DataReceived;

            _exitProcessMsgThread = true;
            _exitProcessRecordThread = true;

            GC.Collect();
        }

        public void Dispose()
        {
            Stop();
        }

        static readonly DataRecipient instance = new DataRecipient();
        /// <summary>
        /// 单例
        /// </summary>
        public static DataRecipient Instance
        {
            get
            {
                return instance;
            }
        }
    }
}
